// 参数接收
const programer = require('commander');

programer
    .version('0.0.1')
    .usage('[options] [value ...]')
    .option('-l, --http_host <string>', 'http ip(192.168.1.15)')
    .option('-p, --http_port <number>', 'http port(1234)', parseInt)
    .option('-H, --tcp_host <string>', 'tcp ip(192.168.1.15)')
    .option('-P, --tcp_port <number>', 'tcp port(2345)', parseInt)
    .option('-M, --mqtt_host <string>', 'mqtt host(192.168.1.15)')
    .option('-Q, --mqtt_port <number>', 'mqtt port(1883)', parseInt);
programer.parse(process.argv);

const program = programer.opts();
if (!program.http_port || !program.tcp_port) {
    console.log(process.argv);
    console.log(program.http_port, program.tcp_port);
    programer.help();
    process.exit();
}

// 默认监听到0.0.0.0
program.http_host = program.http_host ? program.tcp_host : '0.0.0.0';
program.tcp_host = program.tcp_host ? program.tcp_host : '0.0.0.0';

if (program.mqtt_host && !program.mqtt_port) {
    program.mqtt_port = 1883;
}

// 时间格式化
Date.prototype.Format = function (fmt) { //author: meizz
    var o = {
        "M+": this.getMonth() + 1, //月份
        "d+": this.getDate(), //日
        "h+": this.getHours(), //小时
        "m+": this.getMinutes(), //分
        "s+": this.getSeconds(), //秒
        "q+": Math.floor((this.getMonth() + 3) / 3), //季度
        "S": this.getMilliseconds() //毫秒
    };
    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o)
        if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
    return fmt;
}

// 日志输出带时间
console.logt = function (...params) {
    //let tstr = new Date().Format("yyyy-MM-dd HH:mm:ss.S");
    let tstr = new Date().Format("hh:mm:ss.S");
    console.log(tstr, ...params);
}

// 全局 BB-8 WebSocket 服务
let myWsClient = null;

// mqtt连接
if (program.mqtt_host) {
    const mqtt = require('mqtt');
    const clientId = `mqtt_BB-8`;
    const connectUrl = `mqtt://${program.mqtt_host}:${program.mqtt_port}`;
    console.logt(`启用MQTT: ${connectUrl}`);    
    const client = mqtt.connect(connectUrl, {
        clientId,
        clean: true,
        connectTimeout: 4000,
        username: 'emqx',
        password: 'public',
        reconnectPeriod: 1000,
    });

    const topic = 'device/BB-8/command';
    client.on('connect', () => {
        console.logt('MQTT Connected')
        client.subscribe([topic], () => {
            console.logt(`MQTT Subscribe to topic '${topic}'`)
        })
        // client.publish(topic, 'nodejs mqtt test', { qos: 0, retain: false }, (error) => {
        //     if (error) {
        //         console.error(error);
        //     }
        // });
    });
    client.on('message', (topic, payload) => {
        console.logt('MQTT Received Message:', topic, payload.toString());
        myWsClient.send(payload.toString());
    });
}

//创建TCP服务器
const net = require('net');
const server = net.createServer(function (socket) {
    //设置消息内容
    const json_send = { action: 'connect' };
    const json_send_str = JSON.stringify(json_send);

    //发送数据
    socket.write(json_send_str, function () {
        const writeSize = socket.bytesWritten;
        console.logt("Soscket 数据发送成功，发送的数据为：" + json_send_str + "; 数据长度为：" + writeSize);
    });

    //监听data事件
    socket.on("data", function (data) {
        // 接受的数据长度
        const readSize = socket.bytesRead;

        //打印数据
        console.logt("Soscket 接收到数据为：" + data.toString(), "；接收的数据长度为：" + readSize);

        // 转发数据
        if (myWsClient) {
            myWsClient.send(data.toString());
        }
        // ws_server.broadcast(data.toString());

        let json_repo = { action: 'sended' };
        let json_repo_str = JSON.stringify(json_repo);

        //发送数据
        socket.write( data.toString(), function () {
            const writeSize = socket.bytesWritten;
            console.logt("Soscket 数据转发成功，转发的数据为：" +  data.toString() + "; 数据长度为：" + writeSize);
        });
    });
}).listen(program.tcp_port, function () {
    console.logt("Socket 服务正在监听中。。。");
});

// web服务器建立
var http = require('http');
var fs = require('fs');

//创建服务器
const http_server = http.createServer(function (request, response) {
    //解析请求，包括文件名
    if (request.headers.connection == 'Upgrade') {
        response.write(`{"msg":"Websocket", "host":"${program.http_host}", "port":${program.http_port}, "status":"ok"}`);
        return;
    }

    // var pathname= url.parse(request.url).pathname;
    const request_url = new URL(request.url, `http://127.0.0.1:${program.http_port}/`);
    let pathname = request_url.pathname;

    if (pathname == "" || pathname == "/") {
        pathname = "/index.html";
    }

    //获取后缀，判断是js还是css文件，如果目录结构不同，此处需要修改
    var firstDir = pathname && pathname.split('/')[1];
    var ContentType = { 'Content-Type': 'text/html;charset=utf-8' };

    //从文件系统中去请求的文件内容
    let filename = pathname.substr(1);

    //输出请求的文件名
    console.logt("Web Request for " + pathname + "  received. firstDir: " + firstDir + " filename:" + filename);

    if (String(filename).match(/\.(html|js|css|svg|webmanifest|png)$/)) {
        let is_binary = false;
        if ((firstDir && firstDir === 'static') || filename.match(/\.css$/)) {
            ContentType = { 'Content-Type': 'text/css' };
        }
        else if ((firstDir && firstDir === 'js') || filename.match(/\.js$/)) {
            ContentType = { 'Content-Type': 'application/x-javascript' };
        }
        else if ((firstDir && firstDir === 'img') || filename.match(/\.png$/)) {
            ContentType = { 'Content-Type': 'image/png' };
            is_binary = true;
        }
        else if ((firstDir && firstDir === 'svg') || filename.match(/\.svg$/)) {
            ContentType = { 'Content-Type': 'image/svg+xml' };
        }

        ContentType['Request-Filename'] = filename;

        fs.readFile(filename, function (err, data) {
            if (err) {
                console.logt(err);
                response.writeHead(404, { 'Content-Type': 'text/html' });
            }
            else {
                response.writeHead(200, ContentType);
                response.write(is_binary ? data : data.toString());
            }
            response.end();
        });
    } else {
        response.writeHead(404, { 'Content-Type': 'text/html' });
        response.end();
    }
}).listen(program.http_port, program.http_host ? program.http_host : '0.0.0.0');
console.logt(`Web Server running at http://${program.http_host ? program.http_host : '0.0.0.0'}:${program.http_port}/ .`);

//  添加 WebSocket 转发
http_server.addListener('upgrade', (req, res, head) => console.logt('Websocket UPGRADE:', req.url));

//WebSocket服务建立
const WebSocket = require('ws');
const ws_server = new WebSocket.Server({ server: http_server, path: '/' });
ws_server.on('connection', function connection(ws, req) {
    const ip = req.socket.remoteAddress.replace(/::ffff:/, '');
    const port = req.socket.remotePort;
    const clientName = ip + ":" + port;
    const protocol = req.headers['sec-websocket-protocol'];

    if (protocol == 'BB-8') {
        console.logt(`Websocket 【${protocol}】 ${clientName} is connected`);
        myWsClient = ws;
    } else {
        console.logt(`Websocket ${protocol} ${clientName} is connected`);
    }

    // 发送欢迎信息给客户端
    ws.send(`{"msg":"Welcome, ${clientName}", "host":"${program.http_host}", "port":${program.http_port}, "status":"ok"}`);

    // 监听客户端信息
    ws.on('message', function incoming(message) {
        console.logt(`Websocket received: ${message} from ${clientName}`);
        let json = JSON.parse(message);
        if (protocol != 'BB-8' && 'target' in json && json.target=='BB-8' && myWsClient) {
            myWsClient.send(message);
        }
    });
});
ws_server.broadcast = function (data) {
    ws_server.clients.forEach(client => client.send(data));
};
